* p4 Functions for Managing Processes and Clusters::
* Functions for Message Passing::
* Functions for Shared Memory::
* Functions for Timing p4 Programs::
* Functions for Debugging p4 Programs::
* Miscellaneous Functions::
* Fortran Interface::
* Faster Startup with the Secure Server::
* Utilities for Managing a p4 Session::
* Creating Logfiles for Upshot::
* Machine-Specific Notes::
* Some Common Problems and their Solutions::
* Concept Index::
* Function Index::
File: p4.info Node: Introduction, Prev: , Up: Top, Next: Structure of the Distribution Directory
Introduction
============
P4 is a library of macros and subroutines developed at Argonne National
Laboratory for programming a variety of parallel machines. Its
predecessor was the m4-based "Argonne macros" system described in the
Holt, Rinehart, and Winston book {Portable Programs for Parallel
Processors}, by Lusk, Overbeek, et al., from which p4 takes its
name[lusk-overbeek:p4-book]. The current p4 system maintains the
same basic computational models described there (monitors for the
shared-memory model, message-passing for the distributed-memory model,
and support for combining the two models) while significantly increasing
ease and flexibility of use. *Note Getting Started:: for a simple example.
P4 is intended to be portable, simple to install and use, and efficient. It
can be used to program networks of workstations, advanced parallel
supercomputers like the Intel Touchstone Delta and the Alliant Campus
HiPPI-based system, and single shared-memory multiprocessors. It has
currently been installed on the following list of machines: Sequent Symmetry
(Dynix and PTX), Encore Multimax, Alliant FX/8, FX/800, and FX/2800, Cray
X/MP, Sun, NeXT, DEC, Silicon Graphics, HP, and IBM RS6000 workstations,
Stardent Titan, BBN GP-1000 and TC-2000, Intel IPSC/860, Intel Touchstone
Delta, Alliant Campus, and Thinking Machines' CM-5. It will soon be ported to
to the Intel Paragon. It is not difficult to port to new systems. Although
p4 tries to be completely portable, there are a small number of
specific exceptions (*Note Machine-Specific Notes::) that may need to be taken
into account on a given machine.
You can obtain the complete distribution of p4 by anonymous ftp from
`info.mcs.anl.gov'. Take the file `p4.tar.Z' from the
directory `pub/p4'. The distribution contains all source code,
installation instructions, this reference manual, and a collection of
examples in both C and Fortran. `Alog' is included in the
distribution with p4. The file `upshot.tar.Z' contains display
facilities that can be used with p4 and other systems.
To ask questions about p4, report bugs, contribute examples, etc., you can
send mail to `p4@mcs.anl.gov'.
The current release is version 1.2. You can check which version of the source
code you have by looking at the file `lib/p4_patchlevel.h' in the
distribution. You can check which version of the object code you have linked
to by running any p4 program with the command-line option `-p4version'
(*Note Command-Line Arguments::).
Salient features of the current release of p4 include:
* `xdr' support for heterogeneous networks
* manual enhanced and converted to latex format
* Emacs info version of the manual for on-line help
* SYSV IPC support added for several machines (for shared-memory
multiprocessing on workstations that support multiple processors)
* instrumentation added for automatic logging/tracing
* automatic or user control of message-passing/buffer-management
* high-resolution clock support for several machines
* error/interrupt handling
* an optional secure server for quick startup
A useful companion system is the `alog/upshot' logging and X-based trace
examination facility. (*Note Creating Logfiles for Upshot::.)
File: p4.info Node: Structure of the Distribution Directory, Prev: Introduction, Up: Top, Next: Installing p4
Structure of the Distribution Directory
=======================================
The p4 source code distribution contains the following files and
subdirectories:
Makefile
The makefile for making the p4 system, doing the installation,
and making makefiles for user applications.
OPTIONS
A file controlling various compile-time options, such as
whether System V shared-memory operations are to be enabled, whether system
debug message printing is to be enabled, and whether automatic
instrumentation of p4 operations for the `upshot' logging and tracing
program is to be done.
README
General instructions.
alog
Source code for the ALOG tracing package.
bin
Scripts for starting and killing servers, killing runaway p4
processes, merging `upshot' logfiles, and other useful utilities.
contrib
Examples contributed by p4 users.
contrib_f
Fortran examples contributed by users.
doc
The man page, together with this manual and supporting files.
include
The include directory for making p4 applications. Most of
these are (hard) links into the `lib' directory.
lib
The source code for the p4 system.
lib_f
The Fortran interface for p4.
messages
A basic set of message-passing examples in C.
messages_f
A basic set of message-passing examples in Fortran.
monitors
A basic set of shared-memory examples in C.
servers
The secure and insecure servers.
usc
The portable microsecond clock routines.
util
Assorted supporting files, particularly for making the p4
distribution.
File: p4.info Node: Installing p4, Prev: Structure of the Distribution Directory, Up: Top, Next: Getting Started
Installing p4
=============
In this section we describe how to install the p4 library, either for
your own personal use or for the use of everyone at your site. In the
first case you do not need any super-user privileges. In the second
case, you may or may not, depending on how things are configured at
your site. We also describe how to install and run the examples that
come with p4, the online help system (this manual as an emacs info-file)
and how to build a working directory for your own programs yet share
the installed copy of p4 with other users.
* Menu:
* Installing the p4 System::
* Installing the Documentation::
* Examples included with the Distribution::
File: p4.info Node: Installing the p4 System, Prev: , Up: Installing p4, Next: Installing the Documentation
Installing the p4 System
------------------------
To build p4, position yourself in the `p4' directory and type:
make all MACHINE=<machine>
where <machine> is one of the machine names listed in
`p4/util/machines', currently:
SUN
Sun-3, Sun386i, Sparc-1, or Sparc-2 workstations
HP
HP workstations
DEC5000
Dec 5000 workstations
NEXT
68030- or 68040-based NeXT workstations
RS6000
IBM RS 6000 series workstations
IBM3090
IBM 3090 running IBM's version of UNIX, AIX
BALANCE
Sequent Symmetry shared-memory multiprocessor
SYMMETRY
Sequent Symmetry shared-memory multiprocessor
SYMMETRY_PTX
Sequent Symmetry shared-memory multiprocessor PTX OS
MULTIMAX
Encore Multimax shared-memory multiprocessor
GP_1000
BBN GP-1000
TC_2000
BBN TC-2000
TC_2000_TCMP
BBN TC-2000 with the TCMP message-passing library
IPSC860
Intel IPSC/860 (nodes only)
IPSC860_SOCKETS
Intel IPSC/860 with socket libraries on the nodes
DELTA
Intel DELTA
TITAN
Stardent Titan
SGI
Silicon Graphics workstations
CRAY
Cray X/MP
FX8
Alliant FX/8
FX2800
Alliant FX/2800 or FX/800
FX2800_SWITCH
Alliant FX/2800 or FX/800, with CAMPUS HiPPI switch
KSR
Kendall Square KSR-1
CM-5
Thinking Machines' CM-5
For example:
make all MACHINE=SYMMETRY
The `all' is optional, for example
make MACHINE=SEQUENT
This will create a machine-dependent `Makefile' in each subdirectory,
make the p4 library, and compile and link a subset of the examples.
To add a new machine type, or to change the characteristic parameters
associated with an existing one, you can edit the file
`p4/util/defs.all'.
To save disk space, various intermediate object files can be removed with
make clean
The system can be restored to its original, machine-independent state with
make realclean
Note that this removes the machine-dependent Makefiles in each directory, so
the operation is not idempotent.
It is also possible to install (or clean) only some of the directories:
make all MACHINE=SUN DIRS=messages
make clean DIRS='monitors messages'
To install only the Makefiles in all subdirectories, use:
make makefiles MACHINE=<machine>
directory everything that is needed to compile and link p4 programs,
do:
make install INSTALLDIR=<dir>
minimal set of directories, copy the relevant `.a' and `.h' files
into it, and test the installation by mking a small set of examples.
*Note Getting Started:: for instructions on how to run some example
programs after you have installed p4.
File: p4.info Node: Installing the Documentation, Prev: Installing the p4 System, Up: Installing p4, Next: Examples included with the Distribution
Installing the Documentation
----------------------------
The directory `p4/doc' contains this manual as well as files that
require installation. This manual was prepared with the
`latexinfo' package from GNU emacs; thus it can be made available online
through `info'. The files in `p4/doc' are:
p4.tex
the latex source for this manual, which uses the latexinfo style
latexinfo.sty
the sytle file needed to latex this manual
p4.info
the `info' version of this manual, ready to be put
into the directory where `info' files are kept at your site. Check
the value of your `emacs' variable INFO-DIRECTORY.
p4.txt
plain ascii text of the manual, in case nothing else works.
p4.1
unix man page for the p4 library
p4f.1
unix man page for the Fortran interface to p4
The Postscript version of this manual is available by anonymous `ftp'
from `info.mcs.anl.gov', in the directory `pub/p4'. The file to
get (in binary mode) is `p4man.ps.Z'.
File: p4.info Node: Examples included with the Distribution, Prev: Installing the Documentation, Up: Installing p4, Next:
Examples included with the Distribution
---------------------------------------
A good way to see how various p4 functions are used is to look at the example
programs included in the distribution. The `p4/monitors' directory
contains shared-memory examples written in C that use monitors, including one
instrumented with ALOG. The `p4/messages' subdirectory contains
message-passing examples written in C. The programs in `p4/messages_f'
are Fortran message-passing examples, and the `p4/contrib' and
`p4/contrib_f' directories contain a number of miscellaneous examples
contributed by users. In each directory there is a `README' that
describes the individual examples.
File: p4.info Node: Getting Started, Prev: Installing p4, Up: Top, Next: Specifying Processes in the Procgroup File
Getting Started
===============
The easiest way to get started with p4 is to play with some of the
sample programs provided with the system.
* Menu:
* A Message-Passing Example::
* Analysis of the Program::
File: p4.info Node: A Message-Passing Example, Prev: , Up: Getting Started, Next: Analysis of the Program
A Message-Passing Example
-------------------------
We will begin with a message-passing example in the sub-directory named
`p4/messages'. The code for the program is in the files `sr_test.c'
and `sr_user.h'.
Program Description
-------------------
As the name implies, this program is an example of p4's send/receive
functionality. Briefly, it is a simple program that runs a master
process and some slave processes. The master and the set of slaves
form a ring of processes in which the master reads a message from stdin
and sends a copy of the message to the first slave, which passes it on;
the last slave passes the message back to the master. If the master
receives an undamaged copy of the message, it assumes that all went
well, and reads another message. Note that the ring of processes is a
logical structure in which each process assumes that its
predecessor in the ring is the process with the next lower id, and
its successor is the process with the next higher id. The master
has id 0 (zero) and has the process with the largest id as its
predecessor.
File: p4.info Node: Analysis of the Program, Prev: A Message-Passing Example, Up: Getting Started, Next:
Analysis of the Program
-----------------------
The first executable p4 statement in a program should be:
p4_initenv(&argc,argv);
This initializes the p4 system and allows p4 to extract any command
line arguments passed to it, e.g. debugging parameters.
Similarly, the last executable p4 statement in a program should be:
p4_wait_for_end();
This waits for termination of p4 processes and performs some cleanup
operations.
The procedure `p4_get_my_id' returns the unique integer id assigned
to the calling process by p4.
The statement:
p4_create_procgroup();
reads a procgroup file that the user builds and creates the set of
slaves described in that file. Obviously this statement must be
executed before any slaves can be assumed to exist. This procedure
is the method you must use to create processes that do message-passing.
The procedure `p4_clock' returns an integer that represents
wall-clock time in milliseconds. It is typically used to retrieve the
time before and after some work, the difference representing the time to
do that work. Note that there is also a `p4_ustimer' that is useful on
those machines that support a microsecond timer.
The procedures `p4_send' and `p4_sendr' are two of several
p4 procedures that are available for sending messages to other processes.
They take as arguments the message type, the id of the "to" process,
the address of the message, and the message length.
The procedure `p4_recv' receives a message from another process and
sets the values of all four parameters. `P4_recv' will automatically
retrieve a buffer in which to place a received message, thus
`p4_msg_free' may be called to free that buffer when it is no longer
needed.
The procedure `p4_num_total_slaves' is one of several procedures that
the user can invoke to determine information about the current execution.
To run this program, you need to create a procgroup file that describes
where all slave processes are to be executed
(*Note Specifying Processes in the Procgroup File::). We will assume that
you have an example procgroup file (named `procgroup') in the
`p4/messages' directory, and can run `sr_test' by merely typing:
sr_test
If the procgroup file is elsewhere, then you must type:
sr_test -pg {pathname_of_procgroup_file}
Another example that is made by default is the program `systest'. It
tests a number of the message-passing features of p4.
File: p4.info Node: Specifying Processes in the Procgroup File, Prev: Getting Started, Up: Top, Next: Developing a Simple p4 Program
Specifying Processes in the Procgroup File
==========================================
The procgroup file is the only portion of the interface that is very
likely to change through multiple versions of p4. As new architectures
are supported, it is hoped that we can merely alter the procgroup file
format to reflect any new features. (Of course new procedure calls may
also be required, but existing procedure calls will remain unchanged
when possible).
The current format of a procgroup file is as follows:
local n [full_path_name] [loginname]
remote_machine n full_path_name [loginname]
.
.
.
On cube and mesh architectures, the program is started via some
special command executed from the host machine. In such cases, the
procgroup file name can be specified to the special command line along
with the program name (see for example the `runcube' and `rundelta'
shell scripts in the `p4/messages' subdirectory). In those cases
where no special command is required, no special handling is required
for the procgroup filename.
The first line of a procgroup file must be "local n" where n is the
number of slave processes that are in the same cluster as the master.
The full path name on the "local" line is ignored on machines other
than cube and mesh machines. The subsequent lines contain either
three or four fields:
1. the name of a remote machine on which slave processes are to be created.
2. the number of slaves that are to be created on that machine,
i.e. be in the same cluster (note that on machines that support it,
the processes in a cluster will share memory)
3. the full path name of the executable slave program
4. optionally, the user login name on the remote machine, if different from
that on the host machine.
As an example, let's assume that you have a network of three Sun
workstations named sun1, sun2, and sun3. We will also assume that you
are working on sun1 and plan to run a master process there.
If you would like to run one process on each of the other Suns, then you
might code a procgroup file that looks like:
# start one slave on each of sun2 and sun3
local 0
sun2 1 /home/mylogin/p4pgms/sr_test
sun3 1 /home/mylogin/p4pgms/sr_test
Lines beginning with `#' are comments.
Next, let's assume that you have a Sequent Symmetry (named symm) and an
Encore Multimax (named mmax). We will also assume that you are working
on symm, and plan to run the master there. If you would like to run
two processes on symm (in addition to the master) and two on mmax, then
you might code a procgroup file that looks like:
local 2
mmax 2 /mmaxfs/mylogin/p4pgms/sr_test
P4 also permits you to treat the symmetry as a remote machine even when
you are running the master there. Thus, you might code a procgroup file
as follows:
local 2
symm 2 /symmfs/mylogin/p4pgms/sr_test
mmax 2 /mmaxfs/mylogin/p4pgms/sr_test
In this example, there are seven processes running. Five of the
processes are on symm, including the master. Two of the processes on
symm are in the master's procgroup and two are running in a separate
procgroup as if they were on a separate machine. Of course, the last
two are running on mmax.
Some notes about the contents of the procgroup file should be made at
this point. First, the value of `n' on the local line can be zero,
i.e. the master may have no local slaves. Second, the local machine
may be treated as if it is a remote machine by merely entering it in
some line as a remote machine. Third, a single machine may be treated
as multiple remote machines by having the same remote machine name
entered on multiple lines in the procgroup file. Fourth, if a single
machine is listed multiple times, those processes specified on each
line form a single cluster (share memory). Fifth, the cluster size
specified for a uniprocessor should be 1, because all slaves in a
cluster are assumed to run in parallel and to share memory.
We refer to the original (master) process as the "big master". The
first process created in each cluster is the "remote master" or the
"cluster master" for that cluster.
All p4-managed processes (see the procedure `p4_create_procgroup')
have unique integer id's beginning with 0.
The processes within a cluster are numbered consecutively.
File: p4.info Node: Developing a Simple p4 Program, Prev: Specifying Processes in the Procgroup File, Up: Top, Next: Command-Line Arguments
Developing a Simple p4 Program
==============================
The real fun associated with any computing environment arrives when you
actually type in a program and run it yourself. We will assume that
you have successfully installed p4 on your own system and are ready to
write a small program, compile it, and run it.
* Menu:
* A Minimal Example::
* A More Complicated Example::
File: p4.info Node: A Minimal Example, Prev: , Up: Developing a Simple p4 Program, Next: A More Complicated Example
A Minimal Example
-----------------
We will start with a tiny program in which the slave processes do no work, and
then expand its capabilities. Edit a file called `p4simple.c' and type:
#include "p4.h"
main(argc,argv)
int argc;
char **argv;
{
p4_initenv(&argc,argv);
if (p4_get_my_id() == 0)
p4_create_procgroup();
slave();
p4_wait_for_end();
}
slave()
{
printf("Hello from %d++",p4_get_my_id());
}
This is one of the simplest p4 programs that you can write. Let's
examine it. The `#include "p4.h"' statement must appear in all
programs that use any p4 features. The procedure `p4_initenv'
must be invoked before any other p4 procedures, and
`p4_wait_for_end' must be invoked after all p4 processing is
completed. The `p4_get_my_id' returns a unique integer id for
each process, beginning with 0. The procedure
`p4_create_procgroup' should only be invoked once (by process 0),
and is responsible for creating all other processes. The way in which
`p4_create_procgroup' determines how many other processes there
should be, and where they should run, will be discussed shortly.
All processes that this program executes invoke the slave procedure,
including process 0. Thus, in this program, the master process acts
just like all other processes once it gets the environment
established.
To understand how things get started, let's consider two separate
situations. In the first situation, all processes are running on a
single machine. Then, when process 0 starts, it executes the
`p4_create_procgroup' procedure to start all other slaves. The other
slaves are started on the same machine by means of a UNIX {fork},
and they immediately invoke a procedure named slave. Thus, these local
slaves do not ever execute the main procdure.
In the second situation, there may be slaves running both on the same
machine as process 0, and slaves running on other machines as well.
In this situation, the first slave running on a remote machine will
need to execute the main procedure. It will discover that it is not
process 0. However, as part of initialization, process 0 will
direct it to fork any additional slaves required on the same machine.
In some ways, the above example can be used a a prototype for all p4 programs,
just by varying the content of the `slave' routine. The routine name
`slave' is built into p4 in order to enable the same code to be run on
shared-memory machines via `fork' or on remote machines via `rsh'.
Different wrappers are automatically put around the `slave' code. These
wrappers depend on the user code being called `slave'. Thus your p4
program must contain a subroutine called `slave' in order to link
properly.
File: p4.info Node: A More Complicated Example, Prev: A Minimal Example, Up: Developing a Simple p4 Program, Next:
A More Complicated Example
--------------------------
Now, let's make the slave process a little bit more interesting. Let's
assume that we have `nprocs' slaves with ids
0, 1, 2, ... `nprocs' -1. And, we want to write a program in which
every process sends a single message to every other slave, and then
receives a message from every other slave. We might alter the code for
the slave procedure to be the following:
slave()
{
char *incoming, *msg = "hello";
int myid, size, nprocs, from, i, type;
myid = p4_get_my_id();
nprocs = p4_num_total_ids();
for (i=0; i < nprocs; i++)
{
if (i != myid)
p4_send(100, i, msg, strlen(msg)+1);
}
for (i=0; i < nprocs - 1; i++)
{
type = -1;
from = -1;
incoming = NULL;
p4_recv(&type,&from,&incoming,&size);
printf("%d received msg=:%s: from %d++",myid,incoming,from);
p4_msg_free(incoming);
}
}
This program demonstrates several features of p4's support for
message-passing. Before we get into the specifics however, let's
examine the overall logic of the program. Each process determines its
own id and the total number of processes executing in this run
(including process 0). Then, in the first for-loop, each process sends
a single message to each of the other processes. Finally, in the
second for-loop, each process receives a message from each of the other
processes.
The `p4_send' call requires 4 arguments:
* a message type (arbitrarily chosen to be 100 here)
* the id of the process to receive the message
* the message itself
* the size of the message
The use of `p4_recv' is slightly more complicated. First, we
assign -1 to each of the parameters type and from. This is done
because -1 represents a wildcard value indicating we are willing to
receive a message of any type from any process. Here, we could have
coded type to be 100, and specified from equal to the value of i each
time through the loop (skipping our own id). By setting incoming to
NULL, we have also indicated to `p4_recv' that we do not have a
buffer in which to place the received message, so `p4_recv' should
obtain a buffer for us and place the message in that buffer.
`p4_recv' treats these three parameters as both input and output
values. Thus, it alters the value of each such that type and from
indicate the type of message received and the id of the process that
sent it. The value of `incoming' is altered to point to the
buffer where the message was placed. The `size parameter' is
strictly an output parameter and iindicates the size of the received
message. It is possible for the user to provide his own buffer; this
will be demonstrated later.
Finally, note that `p4_msg_free' frees the message buffer obtained by
`p4_recv.' The procedure `p4_msg_free' should be called only after
the contents of the message are no longer needed. `P4_msg_free' should
be used to free these buffers because, although a user only sees the data
portion of a message, p4 internally represents a message as a structured data
item.
To compile and link this program for execution, you need to create a
makefile. We will assume that you have installed p4 in
`/usr/local/p4' and that you have typed the program above into a
file name `p4simple.c' in the directory
`/home/mylogin/p4pgms'.
To build your makefile, copy the file
/usr/local/p4/messages/makefile.proto
into your working directory. This is a prototype makefile that
contains machine-independent information, and which p4 can use to build a
machine-specific makefile for your program. This prototype makefile contains
information about several sample programs that demonstrate
message-passing in p4. If you edit this file, you will see information
for making a program named `sr_test'. Do a global change of
`sr_test' to `p4simple'. You should also change the value of
`P4_HOME_DIR'. It should contain the full
pathname of the p4 system, e.g. `/usr/local/p4'. Now change
directories to `/usr/local/p4' and type:
make makefiles MACHINE=<machine_type> DIRS=/home/mylogin/p4pgms
where `<your_machine_type>' is the machine type that you specified when
you installed p4 on your machine. Now, you should be able to change
back to your directory and see a file named Makefile there.
You should then be able to type:
make p4simple
There is one last piece missing before you can execute your program.
Recall that `p4_create_procgroup' needs to know how many processes
to start and where to start them; it reads a file (called a
"procgroup file") to gather this information. p4 always assumes
that you have a master process, and that you describe the slave
processes (process groups) in the procgroup file. You can name a
procgroup file any name you choose, but `procgroup' is the default
name. The information contained in procgroup files can get fairly
involved, but if you have a computer that supports shared memory among
processes, then you can code a very simple example at first.
Let us suppose first that you want to run your program on a network of
workstations. Then your procgroup should look something like:
local O
some.network.machine 1 /home/me/p4progs/p4simple
This file indicates that you wish to run only the master on the local machine
(the one you are logged into when you execute the program) and one slave on
the machine `some.network.machine'.
Now, all you have to do to run your program is type:
p4simple
You should see a line printed each time a process receives a message
from another process (on some machines, there may be a restriction that
only one process can do I/O, however such restrictions are not
common). Experiment by changing the number of slaves indicated in the
procgroup file.
You may notice that even a small p4 program becomes large when linked
with the p4 library. You might consider using `strip' to reduce
the size or removing `-g' from the CFLAGS in the makefile.
File: p4.info Node: Command-Line Arguments, Prev: Developing a Simple p4 Program, Up: Top, Next: The p4 Function Library
Command-Line Arguments
======================
The command-line arguments to a p4 program are all optional.
-help get this information and the version number, then exit
-pg procgroup_file
-dbg set debug level
-rdbg set remote debug level
-gm set globmemsize
-dmn provide local domainname
-outfile output file for master
-routfile output file prefix for remote masters
-ssport port# private port number for secure server
-p4log enable internal p4 logging by alog
-p4version print the current p4 version number
File: p4.info Node: The p4 Function Library, Prev: Command-Line Arguments, Up: Top, Next: p4 Functions for Managing Processes and Clusters
The p4 Function Library
=======================
* Menu:
* Overview of the Library::
* Return Codes from p4 Functions::
File: p4.info Node: Overview of the Library, Prev: , Up: The p4 Function Library, Next: Return Codes from p4 Functions
Overview of the Library
-----------------------
In the following sections, we provide details for each p4 function in the
library. The procedures are gathered into the following groups:
* Functions for managing processes and clusters
* Functions for message passing
* Functions for shared memory
* Functions for timing p4 programs
* Functions for debugging p4 programs
* Miscellaneous functions
* Fortran interface functions
File: p4.info Node: Return Codes from p4 Functions, Prev: Overview of the Library, Up: The p4 Function Library, Next:
Return Codes from p4 Functions
------------------------------
Most p4 functions return -1 if an error occurs. Some, however, call the
function `p4_error' when severe errors occur. This function prints a
message and then attempts to terminate all of the user's processes
*Note Functions for Debugging p4 Programs::.
File: p4.info Node: p4 Functions for Managing Processes and Clusters, Prev: The p4 Function Library, Up: Top, Next: Functions for Message Passing
p4 Functions for Managing Processes and Clusters
================================================
In some situations a p4 procedure will give an error message and then
exit. This is typically done as a result of a failed system call and
handled by calling the p4 procedure named `p4_error' that examines the
return values from socket procedures, etc. Most of the time however,
the procedures simply return a value. Some of the procedures return no
value and thus are declared to return `VOID'. Some of the
procedures return either a pointer to a character string or `NULL';
`NULL' indicates an error. The remaining procedures return an
integer value; (-1) indicates an error.
* Menu:
* Functions for Process Management::
* Functions for Cluster Management::
File: p4.info Node: Functions for Process Management, Prev: , Up: p4 Functions for Managing Processes and Clusters, Next: Functions for Cluster Management
Functions for Process Management
--------------------------------
In this section we describe the p4 functions needed for basic creation and
termination of processes.
int p4_initenv(argc,argv)
int *argc;
char **argv;
should be called by your program before an attempt is made to use
any p4 procedures or data areas. We suggest making it the first executable
statement in your program. `p4_initenv' parses the command line
arguments and extracts the ones intended for p4 ignoring all others (see the
discussion of command line arguments). Note that you pass the address of
`argc' to `p4_initenv' so that it can actually remove its own
arguments before your program looks at them.
int p4_create(fxn)
int (*fxn)();
int p4_create_procgroup()
There are two procedures that you can use to create processes in p4,
`p4_create_procgroup' and `p4_create'. Processes created via
`p4_create' are said to be "user-managed" whereas those created
by `p4_create_procgroup' are "p4-managed". The p4-managed
processes are automatically assigned unique id's (beginning with 0 for
the big master), they have message queues allocated for them so that
they can do message-passing, and they are able to run either on a
shared-memory multiprocessor with the creating process or they can run
on a separate machine. Processes created via `p4_create' do not
have any of these advantages. They must develop their own id's, they
cannot do message-passing, and they can only run on a shared-memory
multiprocessor with the creating process. The only disadvantage of
`p4_create_procgroup' is that you must build a `procgroup'
file describing the set of required slave processes before the master
program begins execution. This eliminates the possibility of
determining late in the execution exactly how many processes you want
to use to solve a problem. Generally, this is not a problem,
especially since we can combine `p4_create_procgroup' and
`p4_create' in the following way: You can use
`p4_create_procgroup' to develop a network of processes that talk
to each other via messages. Each of those processes can create further
processes to help it out as necessary. The original set of processes
communicate with their local slaves through shared data areas and with
each other via message-passing.
`p4_create' receives one argument that is a pointer to a function. It
creates a single new process that executes the indicated function. The
new process may share data areas (in shared memory) with the parent
process. However, the new process is not managed by the p4 system in
the sense that it is not assigned an id, it cannot pass messages, etc.
The only p4 procedure that deals with user-managed slaves is `p4_create'.
No other procedures are even aware of their existence.
`p4_create_procgroup' reads your `procgroup' file to determine the
number of slave processes to create and where they are to be placed. It
builds a procgroup table that describes all created processes and gives
a copy of the table to each process. The processes then use the table
to discover how to communicate with each other (processes in a cluster
can send messages directly through shared memory or some other
vendor-specific mechanism), others communicate via sockets).
An alternative method is to build the table in memory yourself and use
`p4_startup'.
The effect of `p4_create_procgroup' can be obtained in another way if a
system would prefer to use its own way of specifying the locations of
processes. A user may allocate the procgroup data structure and then fill it
in "by hand" rather than by reading a file in p4 procgroup format. The
following procedures support this method of starting processes.
struct p4_procgroup *p4_alloc_procgroup()
allocates a procgroup data structure of the form described in `p4.h'.
The formats of individual entries (`p4_procgroup_entry') are given there
as well.
int 4_startup(pg)
struct p4_procgroup *pg;
starts processes as specified by an an already-created procgroup data
structure allocated by `p4_alloc_procgroup' and filled in by the user
using the structures `p4_procgroup_entry' and `p4_procgroup'.
VOID p4_wait_for_end()
is the p4 termination/cleanup procedure that you should invoke at the
end of every execution of a program that uses p4.
It does some termination processing and then waits for slave processes
to end.
int p4_get_my_id()
returns an integer value representing the id of the process assigned by
the p4 system. If the process is not a p4-managed process, the value
(-1) is returned.
int p4_num_total_ids()
returns an integer value indicating the total number of ids started
by p4 in all clusters, including the big master and all remote masters.
int p4_num_total_slaves()
returns an integer value indicating the total number of processes started
by p4 in all clusters, including all remote masters but not the big master.
File: p4.info Node: Functions for Cluster Management, Prev: Functions for Process Management, Up: p4 Functions for Managing Processes and Clusters, Next:
Functions for Cluster Management
--------------------------------
The p4 system supports the "cluster" model of parallel computation, in
which subsets of processes share memory with one another, with the clusters
communicating via messages. A procgroup file for a program written for the
cluster model might look like this:
local 4
alliant1.abc.edu 5 /home/me/myprog
alliant2.abc.edu 5 /home/me/myprog
encore.somewhere.edu 5 /usrs/me/myprog
This would specify a total of 20 processes, 5 (including the master) running
on the local machine (here assumed to be capable of supporting five processes
that share memory) together with 5 slaves each on three other shared-memory
machines.
VOID p4_get_cluster_ids(start,end)
int *start;
int *end;
receives pointers to two integers. It places the p4-assigned id's of
the first and last ids within the current cluster into the two
arguments (including the remote master).
int p4_get_my_cluster_id()
returns a unique id (relative to 0) within a cluster of p4-managed
processes. Thus, a cluster master will always have a cluster id of 0.
It is not clear that a separate cluster id is really useful, but the
functionality is provided just in case.
BOOL p4_am_i_cluster_master()
returns a BOOL value indicating whether the invoking process is the
"cluster master" process within its cluster.
int p4_num_cluster_ids()
returns an integer value indicating the number of ids in the current
cluster as started by `p4_create_procgroup'.
File: p4.info Node: Functions for Message Passing, Prev: p4 Functions for Managing Processes and Clusters, Up: Top, Next: Functions for Shared Memory
Functions for Message Passing
=============================
P4 supports a set of send/receive procedures. These procedures are
"generic" in the sense that they do not know whether a message must
travel across a network or through shared memory, or via some other
mechanism. They depend on a lower-level set of procedures that handle
local or network (remote) communications. By default, the messages
are assumed to be typed. If the user wishes to use untyped messages,
he can hide the typing by coding some very simple C macros that always
use a single message type.
* Menu:
* Explicit Sending and Receiving of Messages::
* Global Operations::
File: p4.info Node: Explicit Sending and Receiving of Messages, Prev: , Up: Functions for Message Passing, Next: Global Operations
Explicit Sending and Receiving of Messages
------------------------------------------
p4_send(type,to,msg,len)
p4_sendr(type,to,msg,len)
p4_sendx(type,to,msg,len,datatype)
p4_sendrx(type,to,msg,len,datatype)
p4_sendb(type,to,msg,len)
p4_sendbr(type,to,msg,len)
p4_sendbx(type,to,msg,len,datatype)
p4_sendbrx(type,to,msg,len,datatype)
int type, to, len, datatype;
char *msg;
Each of these procedures sends a message. The `type' argument is
an integer value chosen by the user to represent a message type. The
`to' argument is an integer value that specifies the p4-id of the
process that should receive the message. The `len' argument
contains the length of the message to be passed. Note that some of the
procedures have a "b" in their name, e.g. `p4_sendb'. These
procedures assume that the msg is in a buffer that the user obtained
earlier via a `p4_msg_alloc'; otherwise, the buffer is assumed to
be in the user's local space, and may cause the message to be copied
internally. The procedures with an "r" in the name do not return
until an acknowledgement is received from the `to' process (the
"r" stands for rendezvous). Those procedures with an "x" in the
name take an extra argument (datatype) that specifies the type of data
in the message; these procedures will use that information to call XDR
for data conversion if the message is being passed to a machine of a
different architecture, i.e. where the internal representation may be
different.
BOOL p4_messages_available(req_type,req_from)
int *req_type,*req_from;
returns a BOOL value indicating whether the process has any messages available
or not. The parameters `req_type' and `req_from' are both pointers
to integers; they are used as {both} input and arguments. On input,
`req_type' has a value that indicates the type of message that the user
wishes to check for availability (-1 indicates any type). The variable
`req_from' is used similarly to indicate who a message is desired from.
int p4_recv(req_type,req_from,msg,len_rcvd)
int *req_type,*req_from,*len_rcvd;
char **msg;
pointer to a `char'. If this value is NULL, then p4 will allocate the
buffer for the message according to its length. That is, one need not know
ahead of time the length of a message being received. If this value is not
NULL, then it points to a p4 message buffer that the user has obtained via
`p4_msg_alloc'. The `len_rcvd' argument is a pointer to an integer
that is assigned the length of the received message. `Req_type' and
`req_from' are both pointers to integers; they are used as both input and
arguments. On input, `req_type' has a value that indicates the type of
message that the user wishes to receive (-1 indicates any type). It will
block until a message of that type is available. `Req_from' is used
similarly to indicate who a message is desired from. One important note about
this procedure is that it obtains the area in which to place a message, and
the user must explicitly free that area when finished with it (see
`p4_msg_free'). There is an option available with `p4_recv' in
which the user can provide his own buffer rather than having p4 allocate it.
To do this, the user points `msg' to a buffer that he must obtain via a
call to `p4_msg_alloc' (see below). Then he assigns `len_rcvd' a
value which is the length of that buffer. In this case, `len_rcvd' is
both an input and output variable. In addition, no `p4_msg_free' need be
performed if the same buffer is going to be re-used multiple times.
char *p4_msg_alloc(len)
int len;
obtains a pointer to a buffer area that can be used to receive a
message. This procedure should be used for this task because a
message has hidden information which the user is unaware of and
therefore should not use malloc to obatin the area.
VOID p4_msg_free(m)
char *m;
frees the message pointed to by `m.' This procedure should be used
for this task because a message has hidden information which the
user is unaware of and therefore cannot be freed by the user.
File: p4.info Node: Global Operations, Prev: Explicit Sending and Receiving of Messages, Up: Functions for Message Passing, Next:
Global Operations
-----------------
P4 supports a number of operations for dealing with all processes at once.
p4_broadcastx(type, data, data_len, data_type)
int type;
char *data;
int data_len, data_type;
p4_broadcast(type, data, data_len)
int type;
char *data;
int data_len;
provide the ability to broadcast messages like `p4_send' and
`p4_sendx'.
p4_global_op(type,x,nelem,size,op,data_type)
int type;
char *x;
int size, nelem;
int (*op)();
int data_type;
where `op' is one of:
p4_int_absmax_op()
p4_int_absmin_op()
p4_int_max_op()
p4_int_min_op()
p4_int_mult_op()
p4_int_sum_op()
p4_dbl_absmax_op()
p4_dbl_absmin_op()
p4_dbl_max_op()
p4_dbl_min_op()
p4_dbl_mult_op()
p4_dbl_sum_op()
p4_flt_absmax_op()
p4_flt_absmin_op()
p4_flt_max_op()
p4_flt_min_op()
p4_flt_mult_op()
p4_flt_sum_op()
and `data_type' is one of `P4INT', `P4LNG', `P4FLT', or
`P4DBL'.
This collection of routines provide the ability to do a variety of
global operations. See the example programs in subdirectory
`p4/contrib'. They apply the commutative operation `op' globally
to `x' on an element-by-element basis and broadcast the result to
all nodes. That is each process ends up with
for (i=0; i<n; i++)
x[i] = x[node 0][i] op x[node 1][i] op x[node 2][i] op ...
`op' should be of the form
VOID op(char *x, char *y, int nelem)
{
data_type *a = (data_type *) x;
data_type *b = (data_type *) y;
while (nelem--)
*a++ operation= *b++;
}
where `data_type' and `operation' are chosen appropriately.
The order in which nodes apply the operation is undefined (hence
`op' must be commutative). The communication may be internally
sub-blocked so the function `op' should not be hardwired to specific
vector lengths.
This is still a relatively primitive version, which gathers the necessary data
up a balanced binary tree and then uses `p4_broadcast' to send the
results back.
VOID p4_global_barrier(type)
int type;
This procedure takes one argument which is the message type to be
used for internal message-passing. It causes the invoking process to
hang until all processes specified in the procgroup file have invoked
the procedure.
File: p4.info Node: Functions for Shared Memory, Prev: Functions for Message Passing, Up: Top, Next: Functions for Timing p4 Programs
Functions for Shared Memory
===========================
* Menu:
* Managing Shared and Local Memory::
* Shared Memory Data Types::
* Monitor-Building Primitives::
* Some Useful Monitors::
File: p4.info Node: Managing Shared and Local Memory, Prev: , Up: Functions for Shared Memory, Next: Shared Memory Data Types
Managing Shared and Local Memory
--------------------------------
char *p4_malloc(n)
int n;
typically acts like the standard `malloc', but may be rewritten for user
systems that require different operation.
VOID p4_free(p)
char *p;
typically acts like the standard `free', but may be rewritten for
user systems that require different operation.
char *p4_shmalloc()
acts like the standard `malloc' except will obtain shared memory on
machines that support sharing memory among processes. Compare with
`p4_malloc'.
VOID p4_shfree()
frees memory obtained with `p4_shmalloc'. Compare with `p4_free'.
File: p4.info Node: Shared Memory Data Types, Prev: Managing Shared and Local Memory, Up: Functions for Shared Memory, Next: Monitor-Building Primitives
Shared Memory Data Types
------------------------
The abstraction provided by p4 for managing data in shared memory is
"monitors". Good places to learn about the monitor concept in general are
[pbh:architecture] and [hoare:monitors]. The specific approach
taken by p4 is described in [lusk-overbeek:p4-book]. P4 provides several